Skip to content

docs(metadata-protocol): the getMetaItems gate enumerates six rest-server.ts call sites, not five, and names the transitive diagnostics door - #16117

Merged
zhuangjianguo merged 1 commit into
mainfrom
claude/issue-15621-getmetaitems-gate-docblock
Sep 6, 2026
Merged

docs(metadata-protocol): the getMetaItems gate enumerates six rest-server.ts call sites, not five, and names the transitive diagnostics door#16117
zhuangjianguo merged 1 commit into
mainfrom
claude/issue-15621-getmetaitems-gate-docblock

Conversation

@zhuangjianguo

Copy link
Copy Markdown
Collaborator

Fixes #15621

The [#14683] gate docblock above getMetaItems' organizationIdForMetaRead call
called the GET /meta/:type list door "the only door that both gates and reaches
this method"
, and then accounted for "the four remaining" organizationIdForMetaRead
call sites in rest-server.ts. One named plus four remaining is five. That file has
six, and the missing one — GET /meta/diagnostics?type= — both gates and reaches
this method.

Comment only: no behaviour change, no schema change, no exported symbol touched.

Where the text actually is

The card measured the block at :6928-6942 and triage at :6926-6942; #15592 has
landed since. Re-located by text, not by line number, on origin/main at
9b459b791: the enumeration is at packages/metadata-protocol/src/protocol.ts:6800-6816,
inside getMetaItems (declared :6750), immediately above
const orgId = organizationIdForMetaRead(request.type, request.organizationId);.

The census, re-counted here, with its dimension stated

git grep -c organizationIdForMetaRead -- packages/rest/src/rest-server.ts answers
15 on this tree — that is lines, not call sites. (Triage read 13; the total has
moved by two comment mentions since. The call-site count did not move.) Classified
line by line:

kind count lines
import 1 :58
comment mention 8 :3499, :4943, :5007, :5030, :5803, :7073, :7088, :7637
real call site 6 :3504, :5066, :5338, :6239, :7095, :7663

1 + 8 + 6 = 15. The six call sites and what each reaches:

line door reaches
:3504 /meta/:type/:name/layers (via serveMetaItemLayered) getMetaItemLayered :3521
:5066 /meta/diagnostics?type= getMetaItems, transitively
:5338 GET /meta/:type list door getMetaItems :5354
:6239 by-name read getMetaItemCached :6290 / getMetaItem :6413
:7095 /history historyMetaItem :7146
:7663 /diff diffMetaItem :7668

Positive control for the census: the same classification pass over the same file
yields a non-zero count in every one of its three buckets, and the six call-site rows
were each confirmed by reading the destination call rather than by pattern alone.

Why the miss happened, and how the list is now built

The diagnostics door does not call getMetaItems. It calls getMetaDiagnostics,
whose ?type= arm sets targetTypes = [request.type] and loops
getMetaItems({ type: t, organizationId, ... }) per swept type (protocol.ts:6167-6174).
A grep for doors invoking getMetaItems therefore cannot see it.

So the list is now derived from the callee side and stated as closed.
this.getMetaItems( has exactly three callers in this file — getMetaDiagnostics
(:6170), searchAll (:11393) and findReferencesToMeta (:21450) — and a
transitive-closure walk of the class's call graph confirms no other method reaches it
at any depth. In particular none of getMetaItemLayered / getMetaItem /
getMetaItemCached / historyMetaItem / diffMetaItem reaches it, which is what
licenses the surviving "never this method" clause.

Positive control for the closure instrument: run on the same graph, it reports
throwMetadataServiceUnavailable as reached at depth 2 and 3 (by saveMetaItem,
getMetaItemCached, duplicatePackage, migrateStoredMetadata), so the zero result
above is a measurement and not a broken traversal.

findReferencesToMeta is the third caller and gates nothing, deliberately — its door
spends the organization on the reference SOURCES while req.params.type is the TARGET
(rest-server.ts:5803-5816), so it hands the tenant over raw and is not one of the
"already gates" callers this paragraph is about. That is now written down too, so the
next reader does not re-derive it as an omission.

The undeclared hop

getMetaDiagnostics is not a member of MetadataProtocol — neither required nor
optional. Verified on this tree by a brace-balanced scan of the interface
(packages/spec/src/api/protocol.zod.ts:3381-3459): getMetaItems, getMetaItem,
getMetaItemLayered and historyMetaItem are declared there; getMetaDiagnostics is
absent. The door reaches it through a (p as any) cast behind a 501 feature-detect
(rest-server.ts:4922-4927). Real at runtime, invisible to the type system — which is
exactly the kind of path a caller census has to be told rather than left to derive.

Scope

#14683's conclusion is not reopened. It is measured and holds — PR #15619 pinned it
30/30. Only the enumeration backing it was short a caller.

The packages/rest half is tracked separately as #15620 and is not addressed here;
#15620 remains open.

Verification

  • dispatch-gates.mjs --repo objectstack-ai/objectstack derived 40 runnable
    families for this diff (32 by path + 1 by change kind + 7 declared whole-tree).
    38 ran and exited 0. Verdict lines quoted rather than bare exit codes, e.g.
    check-nul-bytes: OK (scanned 7804 text file(s) ... no raw ASCII control bytes)
    and doc authoring guard: ... clean.
  • pnpm check:dts-closure — green: 76/76 declared declaration file(s) present across 14 package(s).
  • pnpm check:dual-build-cjs-loadsNOT MEASURED, not red. It exits 3 with
    Run pnpm build first. This is NOT a pass: nothing was measured. (49 packages have
    no dist in this worktree). It needs a repo-wide build; CI's Build Core covers it.
  • Pins, at commit ebdb9d6ae: pnpm --filter @objectstack/metadata-protocol exec vitest run --maxWorkers=2 src/get-meta-items-org-read-gate.test.ts src/protocol.diagnostics-store-outage.test.ts2 files, 204 tests, 204 passed.

Published-surface measurement (Clause-②)

Clause-②: no — measured, not assumed. Full ablation against the published artefacts:
built at head, swapped this file back to origin/main's copy, rebuilt, compared every
artefact files: ["dist"] ships.

  • Mutation proven on disk before measuring (anchored counts: injected text 0 hits,
    original text 1 hit; blob 89436302 vs HEAD blob 87087b71).
  • index.d.ts, index.d.cts, index.js, index.cjsall four byte-IDENTICAL
    across the ablation.
  • Only index.js.map and index.cjs.map differ, because a sourcemap embeds
    sourcesContent verbatim. Control: pre-existing text from this same docblock that
    this PR never touched (THE HARM IS RESURRECTION, Gate AFTER the fold) is present
    in exactly those two files and absent from the other four — so this is the comment
    family's normal behaviour, not something this diff introduced.
  • Restore proven byte-exact afterwards: blob back to 87087b71, git diff HEAD empty,
    git status --porcelain empty (index included), and the restore leg rebuilt so
    dist matches head.

No declaration moves, no accept/reject behaviour moves, no exported symbol changes.

Changeset

None, and skip-changeset applied: this publishes nothing from any package. Precedent
on this exact shape is b339a38377docs(metadata-protocol): record that hidden does not govern getUiView's default sort, one file, comment-only, no changeset. The
ablation above is the measurement behind the claim.


Generated by Claude Code

…rver call sites, not five, and names the transitive diagnostics door

The `[#14683]` gate docblock above `getMetaItems`' `organizationIdForMetaRead`
call called the `GET /meta/:type` list door "the only door that both gates and
reaches this method", then accounted for "the four remaining"
`organizationIdForMetaRead` call sites in `rest-server.ts`. One named plus four
remaining is five; that file has SIX, and the missing one is
`GET /meta/diagnostics?type=`, which both gates and reaches this method.

It was missed because it does not call `getMetaItems`. It calls
`getMetaDiagnostics`, whose `?type=` arm sets `targetTypes = [request.type]`
and loops `getMetaItems({ type: t, organizationId, ... })` over it, so a grep
for doors invoking `getMetaItems` cannot see it. That hop is also undeclared:
`getMetaDiagnostics` is not a member of `MetadataProtocol`, neither required
nor optional, so the door reaches it through a runtime cast behind a 501
feature-detect - real at runtime, invisible to the type system.

The enumeration is what #14683 offers as evidence that its change is a no-op
for every already-gating caller. That conclusion is measured and holds; only
the enumeration backing it was short a caller.

Comment only: no behaviour change, no schema change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ARYe3yQTQCUFm5qPYNgKaJ
@github-actions github-actions Bot added the size/s label Sep 6, 2026
@claude claude Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 6, 2026
@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/metadata-protocol, touching 9 documentable anchor(s).

31 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: node scripts/docs-audit/affected-docs.mjs --json a4816a79d0396d0fd10696cdf95d66e55aef92d3.

4 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails.

What this run could not see
  • the SDK route bridge reached 61 of 219 client-bound route-ledger rows — the other 158 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 158: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 56 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 102 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 9 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json a4816a79d0396d0fd10696cdf95d66e55aef92d3packageMentionDocs.

Which tree this was computed on

This run read content/docs from ca9565b5c96481a63a7543ca2320f6c5055775a8 — the merge of head ebdb9d6ae7d7e853d2df0dccdf4f684fe928d72d into base a4816a79d0396d0fd10696cdf95d66e55aef92d3, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin ca9565b5c96481a63a7543ca2320f6c5055775a8 && git checkout ca9565b5c96481a63a7543ca2320f6c5055775a8
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin a4816a79d0396d0fd10696cdf95d66e55aef92d3 ebdb9d6ae7d7e853d2df0dccdf4f684fe928d72d && git checkout -B drift-repro a4816a79d0396d0fd10696cdf95d66e55aef92d3 && git merge --no-ff ebdb9d6ae7d7e853d2df0dccdf4f684fe928d72d

node scripts/docs-audit/affected-docs.mjs --json a4816a79d0396d0fd10696cdf95d66e55aef92d3

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs a4816a79d0396d0fd10696cdf95d66e55aef92d3 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@zhuangjianguo
zhuangjianguo marked this pull request as ready for review September 6, 2026 03:01
@zhuangjianguo
zhuangjianguo added this pull request to the merge queue Sep 6, 2026
Merged via the queue into main with commit b45c3f6 Sep 6, 2026
39 checks passed
@zhuangjianguo
zhuangjianguo deleted the claude/issue-15621-getmetaitems-gate-docblock branch September 6, 2026 03:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants